import type { Files, File } from '../../ReactPlayground/PlaygroundContext'
import { transform } from '@babel/standalone'
import { ENTRY_FILE_NAME } from '../../ReactPlayground/files'
export const beforeTranformCode=(filename:string,code:string)=>{//引入React
  let _code=code
  const regexReact=/import\s+React/g
  if((filename.endsWith('.tsx')||filename.endsWith('.jsx'))&&!regexReact.test(code)){
    _code=`import React from \'react\';\n${_code}`
  }
  return _code
}
export const babelTransform = (filename: string, code: string, files: Files) => {//文件名和文件内的代码和之前定义的那个大对象
  //将code进行编译
  let _code=beforeTranformCode(filename,code)//处理代码中没有引入React的情况
  let result = ''
  try {
    //transform用于生成抽象语法树
    result = transform(_code, {
      filename,
      presets: ['react', 'typescript'],
      plugins: [customResolver(files)],//将依赖路径修改为Blob地址
      retainLines: true,//保持原始代码的行号不变，便于调试时能正确映射错误位置
    }).code!//获取转换后的JavaScript代码字符串，使用非空断言操作符( ! )表示结果一定是非空的
    return result
  } catch (err) {
    console.log('编译出错', err);

  }
}
// 编译入口文件


export const compile = (files: Files) => {
  const main = files[ENTRY_FILE_NAME]
  return babelTransform(ENTRY_FILE_NAME, main.value, files)
}
//自定义解析器，用于处理import语句
function customResolver(files: Files) {
  return {
    visitor: {
      ImportDeclaration(path: any) {
        const modulePath = path.node.source.value
        if (modulePath.startsWith('.')) {//如果引入的是'./App'之类的路径
          const file = getModuleFile(files, modulePath)//读取路径文件的内容
          if (!file) return
          if (file.name.endsWith('.css')) {
            path.node.source.value = css2JS(file)//将file转换成一个blob URL
          } else if (file.name.endsWith('.json')) {
            path.node.source.value=json2JS(file)
          } else {
            path.node.source.value=URL.createObjectURL(
              new Blob([babelTransform(file.name,file.value,files)],{type:'text/javascript'}))
          }
        }
      }
    }
  }
}


function css2JS(file: File) {
  const randomId = new Date().getTime()
  const js =  `
    (() => {
      const style = document.createElement('style')
      style.setAttribute('id', 'style_${randomId}_${file.name}')
      document.head.appendChild(style)

      const styleText = document.createTextNode(\`${file.value}\`)
      style.innerHTML = ''
      style.appendChild(styleText)
    })()
  `
  return URL.createObjectURL(new Blob([js], { type: 'text/javascript' }))
}
function json2JS(file: File) {
  const js = `export default ${file.value}`
  return URL.createObjectURL(new Blob([js], { type: 'text/javascript' }))
}
function getModuleFile(files: Files, modulePath: string) {
  let moduleName = modulePath.split('./').pop() || ''
  if (!moduleName.includes('.')) {
    const realModuleName = Object.keys(files).filter(key => {
      return key.endsWith('ts') || key.endsWith('tsx') || key.endsWith('js') || key.endsWith('jsx')
    }).find(key => key.split('.').includes(moduleName))
    if (realModuleName) {
      moduleName = realModuleName
    }
  }
  return files[moduleName]
}

